package main

import (
	"time"

	"github.com/imroc/req"
)

func Login() (code int, user biliUserInfo) {
	print("请扫码登陆")
	code = -1
	uri := "https://passport.bilibili.com/x/passport-tv-login/qrcode/auth_code"
	data := SignHD("app_id=&appkey=dfca71928277209b&build=1250004&c_locale=zh_CN&channel=huawei&code=&device=phone&disable_rcmd=0&extend=&gourl=&local_id=0&mobi_app=android_hd&platform=android&s_locale=zh_CN&spm_id=from_spmid&statistics=%7B%22appId%22%3A5%2C%22platform%22%3A3%2C%22version%22%3A%221.25.0%22%2C%22abtest%22%3A%22%22%7D&ts=" + StrTime())

	type Data struct {
		URL      string `json:"url"`
		AuthCode string `json:"auth_code"`
	}
	type QrcodeRes struct {
		Code    int64  `json:"code"`
		Message string `json:"message"`
		TTL     int64  `json:"ttl"`
		Data    Data   `json:"data"`
	}

	var body QrcodeRes
	client := req.C().SetUserAgent("bilibili").SetTimeout(5 * time.Second)
	_, err := client.R().SetContentType("application/x-www-form-urlencoded").SetBody(data).SetResult(&body).Post(uri)
	if err != nil {
		print(err)
		return
	}
	QRcode(B23(body.Data.URL))
	for i := 0; i < 40; i++ {
		time.Sleep(time.Second * 3)
		var accessToken, refreshToken, cookie string
		code, accessToken, refreshToken, cookie = poll(body.Data.AuthCode)
		if code == 0 {
			user = biliUserInfo{"", accessToken, refreshToken, cookie}
			userCheck(&user)
			print("登陆成功")
			return
		}
	}
	return
}

func poll(authCode string) (code int, accessToken, refreshToken, cookie string) {
	code = -1
	uri := "https://passport.bilibili.com/x/passport-tv-login/qrcode/poll"
	data := SignHD("appkey=dfca71928277209b&auth_code=" + authCode + "&bili_local_id=0&build=1250004&c_locale=zh_CN&channel=huawei&device=phone&disable_rcmd=0&extend=&gourl=&local_id=0&mobi_app=android_hd&platform=android&s_locale=zh_CN&spm_id=from_spmid&statistics=%7B%22appId%22%3A5%2C%22platform%22%3A3%2C%22version%22%3A%221.25.0%22%2C%22abtest%22%3A%22%22%7D&ts=" + StrTime())

	type Cooky struct {
		Name  string `json:"name"`
		Value string `json:"value"`
	}

	type TokenInfo struct {
		Mid          int64  `json:"mid"`
		AccessToken  string `json:"access_token"`
		RefreshToken string `json:"refresh_token"`
		ExpiresIn    int64  `json:"expires_in"`
	}
	type CookieInfo struct {
		Cookies []Cooky `json:"cookies"`
	}
	type Data struct {
		IsNew      bool       `json:"is_new"`
		TokenInfo  TokenInfo  `json:"token_info"`
		CookieInfo CookieInfo `json:"cookie_info"`
	}
	type PollRes struct {
		Code    int64  `json:"code"`
		Message string `json:"message"`
		Data    Data   `json:"data"`
	}

	var body PollRes
	client := req.C().SetUserAgent("bilibili").SetTimeout(5 * time.Second)
	_, err := client.R().SetContentType("application/x-www-form-urlencoded").SetBody(data).SetResult(&body).Post(uri)
	if err != nil {
		print(err)
		return
	}
	code = int(body.Code)
	accessToken = body.Data.TokenInfo.AccessToken
	refreshToken = body.Data.TokenInfo.RefreshToken
	for _, v := range body.Data.CookieInfo.Cookies {
		cookie = cookie + v.Name + "=" + v.Value + ";"
	}
	return
}

func userCheck(user *biliUserInfo) {
	if cookie2buvid(user.Cookie) == "" {
		type Device struct {
			Mid             int64  `json:"mid"`
			LocalID         string `json:"local_id"`
			DeviceName      string `json:"device_name"`
			DevicePlatform  string `json:"device_platform"`
			IsCurrentDevice bool   `json:"is_current_device"`
			LatestLoginAt   string `json:"latest_login_at"`
			Source          string `json:"source"`
		}
		type Data struct {
			Devices []Device `json:"devices"`
		}
		type LoginDevicesRes struct {
			Code    int64  `json:"code"`
			Message string `json:"message"`
			TTL     int64  `json:"ttl"`
			Data    Data   `json:"data"`
		}
		var body LoginDevicesRes
		buvid := "XW" + randStr(35, 5, cookie2uid(user.Cookie))
		uri := "https://api.bilibili.com/x/safecenter/user_login_devices?" + SignHD("access_key="+user.AccessToken+"&appkey=dfca71928277209b&csrf="+cookie2csrf(user.Cookie)+"&disable_rcmd=0&local_id=0&statistics=%7B%22appId%22%3A1%2C%22platform%22%3A3%2C%22version%22%3A%226.83.0%22%2C%22abtest%22%3A%22%22%7D&ts="+StrTime())
		req.C().R().SetResult(&body).Get(uri)
		for _, device := range body.Data.Devices {
			buvid = device.LocalID
			if device.DevicePlatform != "" {
				break
			}
		}
		user.Cookie = user.Cookie + "BUVID=" + buvid + ";"
	}
	if user.UserName == "" {

		type Data struct {
			Name string `json:"name"`
		}

		type MyInfoRes struct {
			Code    int64  `json:"code"`
			Message string `json:"message"`
			Data    Data   `json:"data"`
		}
		var body MyInfoRes
		uri := "https://app.bilibili.com/x/v2/account/myinfo?" + SignHD("access_key="+user.AccessToken+"&appkey=dfca71928277209b&build=6810300&buvid="+cookie2buvid(user.Cookie)+"&c_locale=zh_CN&channel=oppo&disable_rcmd=0&local_id="+cookie2buvid(user.Cookie)+"&mobi_app=android_hd&platform=android&s_locale=zh_CN&statistics=%7B%22appId%22%3A3%2C%22platform%22%3A3%2C%22version%22%3A%226.81.0%22%2C%22abtest%22%3A%22%22%7D&ts="+StrTime())
		req.C().R().SetResult(&body).Get(uri)
		user.UserName = body.Data.Name
	}
}
